
#include    <stdio.h>      /*标准输入输出定义*/
#include    <stdlib.h>     /*标准函数库定义*/
#include    <unistd.h>     /*Unix标准函数定义*/
#include    <sys/types.h>  /**/
#include    <sys/stat.h>   /**/
#include    <fcntl.h>      /*文件控制定义*/
#include    <termios.h>    /*PPSIX终端控制定义*/
#include    <errno.h>      /*错误号定义*/
#include 	<math.h>
#include 	<string.h>
#include    "include/myuart.h"
#include "include/serialbuffer.h"
#include "include/define.h"
#include <QDebug>

MyUart::MyUart():fd_uart(-1)
{
    initUart();
}

MyUart::~MyUart()
{
    close(fd_uart);
}

int MyUart::getFileDescriptor()
{
    return fd_uart;
}

int MyUart::initUart()
{
    if( openUart("/dev/ttySAC3") != SUCCESS )
    {
        return -1;
    }

    if( setSpeed(fd_uart,19200) != SUCCESS )
    {
        return -1;
    }

    if( setparity(fd_uart,8,1,'N') != SUCCESS )
    {
        return -1;
    }

    return 0;
}

/***********************************************************************************
   @brief :            open uart
   @ dev :             uart name
   @return :          file descriptor, -1 if open  FAILED
 */
int MyUart::openUart(const char *dev)
{
    fd_uart = open(dev, O_RDWR);
    if ( fd_uart == -1 )
    {
        qDebug("can't open serial port...");
        return FAILED;
    }
    else
    {
        fcntl(fd_uart, F_SETFL, FNDELAY);   //
        qDebug("open serial port successfully...");
        return SUCCESS;
    }
}


int MyUart::readRawData()
{
    char buffer[255];
    int nread = read( fd_uart, buffer, 255 );
    if ( nread<0 )
    {
        return -1;
    }
    DalRecvBuffer::Instance()->getBuffer().append(buffer,nread);
//    print(DalRecvBuffer::Instance()->getBuffer());
    return nread;
}

int MyUart::writeRawData(QByteArray &msg)
{
    int len = msg.size();
    const char *rawData = msg.constData();
    int nwrite = write(fd_uart,rawData,len);
    if( nwrite != len )
        return -1;
    return 0;
}

// for Baud Rate Settings
const static int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300};
const static int speed_arr[] = {B115200,B57600,B38400, B19200, B9600, B4800, B2400, B1200, B300};
/***********************************************************************************
   @brief :            set uart speed
   @ dev :             uart name
   @return :          file descriptor, -1 if open  FAILED
 */
int MyUart::setSpeed(int fd, int speed)
{
    unsigned int i =0, status=-1;
    struct termios options;
    /*
     * Get the current options for the port...
     */
    tcgetattr(fd, &options);

    for( i=0; i < sizeof(speed_arr)/sizeof(int); i++ )
    {
        if (speed == name_arr[i])
        {
            tcflush(fd, TCIOFLUSH);
            cfsetispeed(&options, speed_arr[i]);
            cfsetospeed(&options, speed_arr[i]);
            status = tcsetattr(fd, TCSANOW, &options);  //return 0 if successful, -1 while  FAILED
            if (status == 0)
            {
                tcflush(fd, TCIOFLUSH); //clear IO buffer
                return SUCCESS;
            }
            else
                break;
        }
    }

    if( i==sizeof(speed_arr)/sizeof(int) )
        qDebug("unsurported speed...");
    return  FAILED;
}


/***********************************************************************************
*@brief   设置串口数据位，停止位和效验位
*@param  fd     类型  int  打开的串口文件句柄*
*@param  databits 类型  int 数据位   取值 为 7 或者8*
*@param  stopbits 类型  int 停止位   取值为 1 或者2*
*@param  parity  类型  int  效验类型 取值为N,E,O,S
*/
int MyUart::setparity(int fd, int databits, int stopbits, int parity)
{
    struct termios options;
    if  ( tcgetattr( fd, &options )  !=  0 )
    {
        qDebug("get serial options failed\n");
        return FAILED;
    }

    options.c_cflag &= ~CSIZE;
    switch (databits) /*设置数据位数*/
    {
    case 7:
        options.c_cflag |= CS7;
        break;
    case 8:
        options.c_cflag |= CS8;
        break;
    default:
        fprintf(stderr,"Unsupported data size\n");
        return  FAILED;
    }

    switch (parity)
    {
    case 'n':
    case 'N':
        options.c_cflag &= ~PARENB;   /* Clear parity enable */
        options.c_iflag &= ~INPCK;     /* Enable parity checking */
        break;
    case 'o':
    case 'O':
        options.c_cflag |= (PARODD | PARENB);  /* 设置为奇效验*/
        options.c_iflag |= INPCK;             /* Disnable parity checking */
        break;
    case 'e':
    case 'E':
        options.c_cflag |= PARENB;     /* Enable parity */
        options.c_cflag &= ~PARODD;   /* 转换为偶效验*/
        options.c_iflag |= INPCK;       /* Disnable parity checking */
        break;
    case 'S':
    case 's':  /*as no parity*/
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported parity\n");
        return  FAILED;
    }

    /* 设置停止位*/
    switch (stopbits)
    {
    case 1:
        options.c_cflag &= ~CSTOPB;
        break;
    case 2:
        options.c_cflag |= CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported stop bits\n");
        return  FAILED;
    }

    /* Set input parity option */
    if (parity != 'n')
        options.c_iflag |= INPCK;

    options.c_cc[VTIME] = 150; // 15 seconds
    options.c_cc[VMIN] = 0;

    /*disable flow control*/
    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
    options.c_oflag  &= ~OPOST;   /*Output*/


    //修改控制模式，保证程序不会占用串口
    options.c_cflag |= CLOCAL;
    //修改控制模式，使得能够从串口中读取输入数据
    options.c_cflag |= CREAD;

    tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        qDebug("set serial port failed\n");
        return  FAILED;
    }
    return  SUCCESS;
}
